/* 
 * Licensed Materials - Property of IBM
 * (c) Copyright IBM Corporation 2010. All Rights Reserved.
 *
 * Note to U.S. Government Users Restricted Rights:  Use,
 * duplication or disclosure restricted by GSA ADP Schedule
 * Contract with IBM Corp.
 *
 * This code is released under the terms of the Eclipse Public License
 * version 1.0 which can be found at the top level of this project or
 * or at http://www.eclipse.org/org/documents/epl-v10.php
 */

package com.ibm.mining;

import java.util.List;

import org.eclipse.core.runtime.IProgressMonitor;

import com.ibm.team.process.client.IProcessClientService;
import com.ibm.team.process.client.IProcessItemService;
import com.ibm.team.process.common.IDevelopmentLine;
import com.ibm.team.process.common.IDevelopmentLineHandle;
import com.ibm.team.process.common.IIteration;
import com.ibm.team.process.common.IIterationHandle;
import com.ibm.team.process.common.IProcessArea;
import com.ibm.team.process.common.IProjectArea;
import com.ibm.team.process.internal.client.ProcessClientService;
import com.ibm.team.process.internal.common.ProcessArea;
import com.ibm.team.repository.client.IContributorManager;
import com.ibm.team.repository.client.ITeamRepository;
import com.ibm.team.repository.client.TeamPlatform;
import com.ibm.team.repository.common.IContributor;
import com.ibm.team.repository.common.IContributorHandle;
import com.ibm.team.repository.common.IItem;
import com.ibm.team.repository.common.IItemHandle;
import com.ibm.team.repository.common.ItemNotFoundException;
import com.ibm.team.repository.common.TeamRepositoryException;
import com.ibm.team.repository.common.query.IItemQuery;
import com.ibm.team.repository.client.*;
import com.ibm.team.repository.client.internal.*;
import com.ibm.team.repository.client.util.IClientLibraryContext;
import com.ibm.team.scm.client.IBaselineConnection;
import com.ibm.team.scm.client.IChangeHistory;
import com.ibm.team.scm.client.IWorkspaceConnection;
import com.ibm.team.scm.client.IWorkspaceManager;
import com.ibm.team.scm.client.SCMPlatform;
import com.ibm.team.scm.common.IBaseline;
import com.ibm.team.scm.common.IBaselineHandle;
import com.ibm.team.scm.common.IChange;
import com.ibm.team.scm.common.IChangeHistoryEntryChange;
import com.ibm.team.scm.common.IChangeSet;
import com.ibm.team.scm.common.IChangeSetHandle;
import com.ibm.team.scm.common.IComponent;
import com.ibm.team.scm.common.IComponentHandle;
import com.ibm.team.scm.common.IFlowEntry;
import com.ibm.team.scm.common.IFlowNode;
import com.ibm.team.scm.common.IFlowTable;
import com.ibm.team.scm.common.IFolder;
import com.ibm.team.scm.common.IFolderHandle;
import com.ibm.team.scm.common.IRepositoryProgressMonitor;
import com.ibm.team.scm.common.IScmService;
import com.ibm.team.scm.common.IVersionable;
import com.ibm.team.scm.common.IVersionableHandle;
import com.ibm.team.scm.common.IWorkspace;
import com.ibm.team.scm.common.IWorkspaceHandle;
import com.ibm.team.scm.common.dto.IAncestorReport;
import com.ibm.team.scm.common.dto.IBaselineSearchCriteria;
import com.ibm.team.scm.common.dto.IComponentSearchCriteria;
import com.ibm.team.scm.common.dto.INameItemPair;
import com.ibm.team.scm.common.dto.IWorkspaceSearchCriteria;
import com.ibm.team.scm.common.internal.dto.ServiceConfigurationProvider;
import com.ibm.team.workitem.client.IAuditableClient;
import com.ibm.team.workitem.client.IQueryClient;
import java.sql.*;


public class SCMQuerier {
	
	
	IProgressMonitor monitor;
	ITeamRepository repository;
	IWorkspaceManager workspaceManager;
	IBaseline currentBaseline;
	IComponent currentComponent;
	
	ResearchDatabase db;
	
    public static void main(String[] args) throws TeamRepositoryException, SQLException, ClassNotFoundException {
    	System.setProperty("snippetUserAndPassword", "ADMIN");
        TeamPlatform.startup();
        
        try {     
            IProgressMonitor monitor = new SysoutProgressMonitor();
            ITeamRepository repository = TeamRepositoryLogin.login("someurl", "ADMIN", "ADMIN", monitor);
            
            SCMQuerier scmq = new SCMQuerier(repository, monitor);
            
            //TeamQueryModel t = TeamQueryModel.ROOT;
            //IItemQuery query = IItemQuery.FACTORY.newInstance(t);
            
            PostgresResearchDatabase rdb = new PostgresResearchDatabase();
            rdb.connect("jdbc:postgresql://localhost/jazzdata?user=cbird&password=Ucd62010");
            System.out.println("Connected to jazzdata database");
            scmq.db = rdb;
            
            //rdb.createChangeSetTable();
            //rdb.createChangeTable();
            
            //scmq.listContributors();
            
            scmq.listRepoProjects();
            scmq.workspaceManager = SCMPlatform.getWorkspaceManager(repository);
            scmq.doWorkspaceManager(SCMPlatform.getWorkspaceManager(repository));
            
            if (1 == 1)
            	return;
            

            System.out.println("Done outputting");
        //} catch (TeamRepositoryException e) {
        //    System.out.println("Unable to login: " + e.getMessage());
        } finally {
            TeamPlatform.shutdown();
        }
    }
    
    public Object foo() {return 6;}
    
    IScmService scmService;
    IRepositoryProgressMonitor repositoryProgressMonitor;
    public SCMQuerier(ITeamRepository repository, IProgressMonitor monitor) {
    	this.repository = repository;
    	this.monitor = monitor;
    	scmService = (IScmService) ((IClientLibraryContext)repository).getServiceInterface(IScmService.class); 
    	repositoryProgressMonitor = IRepositoryProgressMonitor.ITEM_FACTORY.createItem(monitor);
    }
    
    public void listContributors() throws TeamRepositoryException, SQLException {
    	//db.createContributorTable();
    	IContributorManager contributorManager = repository.contributorManager();	
        System.out.println("Outputting Contributors");
        for (Object o: contributorManager.fetchAllContributors(monitor)) {
        	IContributor contributor = (IContributor) o;
        	System.out.format("userid %1$s name %2$s\n", contributor.getUserId(), contributor.getName());
        	//db.insertContributor(contributor);
        }
    }
    
    public void listRepoProjects() throws TeamRepositoryException {
    	addIndent();
    	IQueryClient queryClient = (IQueryClient) repository.getClientLibrary(IQueryClient.class);
    	IProcessClientService processClient = (IProcessClientService) 
    		repository.getClientLibrary(IProcessClientService.class);
    	IAuditableClient auditableClient = (IAuditableClient) repository.getClientLibrary(IAuditableClient.class);

    	/* this gets a list of all of the project areas */
    	List<IProjectArea> areaHandles = (List<IProjectArea>) ((ProcessClientService)processClient).findAllProjectAreas(IProcessClientService.ALL_PROPERTIES, monitor);
    	
     	for (IProjectArea areaHandle : areaHandles) {
     		IProjectArea area = (IProjectArea) areaHandle.getFullState();
    		System.out.printf("%sArea: %s %s", indent(), area.getName(), area);
    		listMembers(area);
    		doProjectArea(area);    		
    	}
     	subtractIndent();
    }
    
    public void doProjectArea(IProjectArea area) throws TeamRepositoryException {
    	addIndent();
    	for (IDevelopmentLineHandle dlh : area.getDevelopmentLines()) {
    		IDevelopmentLine devLine = (IDevelopmentLine) repository.itemManager().fetchCompleteItem(dlh, IItemManager.DEFAULT, monitor);
    		System.out.printf("%sDevelopment Line: %s %s\n", indent(), devLine.getName(), devLine);
    		doDevelopmentLine(devLine);
    	}
    	subtractIndent();
    }
    
    public void doDevelopmentLine(IDevelopmentLine devLine) throws TeamRepositoryException {
    	addIndent();
    	for (IIterationHandle iterHandle : devLine.getIterations()) {
    		doIteration(iterHandle);
    	}
    	subtractIndent();
    }
    
    public void doIteration(IIterationHandle iterHandle) throws TeamRepositoryException {
    	addIndent();
		IIteration iteration = (IIteration) repository.itemManager().fetchCompleteItem(iterHandle, IItemManager.DEFAULT, monitor);
		System.out.printf("%sIteration: %s %s\n", indent(), iteration.getLabel(), iteration);
		System.out.printf("%s Start Date: %s\n", indent(), iteration.getStartDate());
		System.out.printf("%s End Date: %s\n", indent(), iteration.getEndDate());
		for (IIterationHandle childIterHandle : iteration.getChildren()) {
			doIteration(childIterHandle);
		}
		subtractIndent();
    }
    
    public void doWorkspaceManager(IWorkspaceManager workspaceManager) throws TeamRepositoryException, SQLException {
    	addIndent();
    	indentedPrintf("workspace: %s\n", workspaceManager);
    	IComponentSearchCriteria csc = IComponentSearchCriteria.FACTORY.newInstance();
    	/*for (IComponentHandle ch : workspaceManager.findComponents(csc, 1000, monitor))
    	{
    		doComponent(ch);
     	}*/
    	IWorkspaceSearchCriteria wsc = IWorkspaceSearchCriteria.FACTORY.newInstance();
    	wsc.setKind(wsc.ALL);
    	for (IWorkspaceHandle wsh : workspaceManager.findWorkspaces(wsc, 1000, monitor)) {
    		IWorkspaceConnection workspaceConnection = workspaceManager.getWorkspaceConnection(wsh, monitor);
    		doWorkspace(wsh, workspaceConnection);
    		
    	}
    	subtractIndent();
    }
    
    public void doComponent(IComponentHandle componentHandle) throws TeamRepositoryException, SQLException {
    	addIndent();
    	IComponent component = (IComponent) repository.itemManager().fetchCompleteItem(componentHandle, IItemManager.DEFAULT, monitor);
    	currentComponent = component;
    	indentedPrintf("Component: %s\n", component.getName());
    	if (!component.getName().equals("UA-Server")) {
    		subtractIndent();
    		return;
    	}
    	doFolder(component.getRootFolder());
    	IBaselineSearchCriteria bsc = IBaselineSearchCriteria.FACTORY.newInstance();
    	bsc.setComponentRequired(componentHandle);
    	for (IBaselineHandle baselineHandle : workspaceManager.findBaselines(bsc, 1000, monitor)) {
    		doBaseline(baselineHandle);
    	}
    	subtractIndent();
    }
    
    ServiceConfigurationProvider currentServiceConfigurationProvider;
    public void doBaseline(IBaselineHandle baselineHandle) throws TeamRepositoryException, SQLException {
    	addIndent();
    	IBaseline baseline = (IBaseline) fetchCompleteItem(baselineHandle);
    	this.currentBaseline = baseline;
    	currentServiceConfigurationProvider = ServiceConfigurationProvider.FACTORY.create(currentBaseline);
    	indentedPrintf("Baseline: %s %s %s\n", baseline.getName(), baseline.getCreationDate(), baseline.getComment());
    	IBaselineConnection baselineConnection = workspaceManager.getBaselineConnection(baseline, monitor);
    	doChangeHistory(baselineConnection.changeHistory());
    	subtractIndent();
    }
    
    public void doChangeHistory(IChangeHistory changeHistory) throws TeamRepositoryException, SQLException {
    	addIndent();
    	indentedPrintf("Change History: era=%s\n", changeHistory.getEraIdentifier());
    	for (IChangeHistoryEntryChange changeHistoryEntry : changeHistory.getHistoryDescriptor(true, monitor).recent()) {
    		indentedPrintf(" ChangeHistoryEntry: %s %s\n", changeHistoryEntry.creationDate(), 
    				lookupContributor(changeHistoryEntry.createdBy()).getName());
    		doChangeSet(changeHistoryEntry.changeSet());
    	}
    	subtractIndent();
    }
    
    IChangeSet currentChangeSet;
    
    public void doChangeSet(IChangeSetHandle changeSetHandle) throws TeamRepositoryException, SQLException {
    	addIndent();
    	IChangeSet changeSet = (IChangeSet) fetchCompleteItem(changeSetHandle);
    	currentChangeSet = changeSet;
    	indentedPrintf("ChangeSet: %s %s %s\n", changeSet.getLastChangeDate(), lookupContributor(changeSet.getAuthor()).getName(),
    			changeSet.getComment());
    	
    	if (true) {//db.insertChangeSet(changeSet, currentComponent.getName(), currentBaseline.getName(), currentBaseline.getId(),
    			//lookupContributor(changeSet.getAuthor()).getUserId())) {

	    	for (IChange change : (List<IChange>) changeSet.changes()) {
	    		doChange(change);
	    	}
    	}
    	subtractIndent();
    }
    
    public void doChange(IChange change) throws TeamRepositoryException, SQLException {
    	addIndent();
    	try {
    	String kind;
    	switch (change.kind()) {
    	case IChange.ADD: kind="ADD"; break;
    	case IChange.DELETE: kind="DELETE"; break;
    	case IChange.MODIFY: kind="MODIFY"; break;
    	case IChange.RENAME: kind="RENAME"; break;
    	case IChange.REPARENT: kind="REPARENT"; break;
    	case IChange.NONE: kind="NONE"; break;
    	default: kind="UNKNOWN"; break;
    	}
    	
    	IVersionableHandle versionableHandle;
    	if (change.kind() == IChange.DELETE) {
    		versionableHandle = change.beforeState();

    	} else {
    		versionableHandle = change.afterState();
    		if (versionableHandle == null) {
    			versionableHandle = change.beforeState();
    		}
    	}
    	
    	if (versionableHandle == null) {
    		return;
    	}
    	
 
    	IVersionable versionable = null;
    	//indentedPrintf("Versionable: %s %s\n", versionableHandle, versionableHandle.getStateId());
    	indentedPrintf("Change: %s\n", kind);
    	try {
    		versionable = workspaceManager.versionableManager().fetchCompleteState(versionableHandle, monitor);
    	} catch (Exception e) {
    		System.out.printf("Don't have complete state for change %s uuid %s\n", kind, versionableHandle.getItemId().getUuidValue());
    	}
    	if (versionable != null) {
    		String path = getPath(versionable);
    		indentedPrintf("Change: %s %s\n", kind, path);
    		//db.insertChange(currentChangeSet, path, versionable.getName(), kind);
    	}
    	} finally { 
    		subtractIndent();
    	}
    }
    
    public String getPath(IVersionable versionable) throws TeamRepositoryException {
    	String path = "/";
    	//IRepositoryProgressMonitor repositoryProgressMonitor = IRepositoryProgressMonitor.ITEM_FACTORY.createItem(monitor);
    	//ServiceConfigurationProvider scp = ServiceConfigurationProvider.FACTORY.create(currentBaseline);
    	
    	IAncestorReport ancestorReport = scmService.configurationLocateAncestors(currentServiceConfigurationProvider,
    			new IVersionableHandle[] {versionable}, null, repositoryProgressMonitor)[0];
    	
    	
    	for (INameItemPair pair : (List<INameItemPair>) ancestorReport.getNameItemPairs()) {
    		/* for now, don't worry about grabbing the versionable itself.  Just get the name */
    		//versionable = workspaceManager.versionableManager().fetchCompleteState(pa, monitor);
    		if (pair.getName() != null) {
    			path = path + "/" + pair.getName();
    		}
    	}
    	
    	if (path.length() < 2)
    	{
    		path += versionable.getName();
    	}
    	//indentedPrintf("path is %s\n", path);
    	return path;
    	
    }
    
    public void doFolder(IFolderHandle folderHandle) throws TeamRepositoryException {
    	addIndent();
    	
    	//IFolder folder = (IFolder) repository.itemManager().fetchCompleteItem(folderHandle, IItemManager.DEFAULT, monitor);
    	//indentedPrintf("Folder: %s", folder);
    	subtractIndent();
    }
    
    public void doWorkspace(IWorkspaceHandle workspaceHandle, IWorkspaceConnection workspaceConnection) throws TeamRepositoryException {
    	addIndent();
    	IWorkspace workspace = (IWorkspace) repository.itemManager().fetchCompleteItem(workspaceHandle, IItemManager.DEFAULT, monitor);
    	
    	indentedPrintf("Workspace: %s %s %s %s\n", workspace.isStream() ? "Stream" : "Workspace", 
    			workspace.getName(), workspace.getDescription(), workspace.getOwner());
    	indentedPrintf("flow uuid: %s\n", workspace.getItemId().getUuidValue());
    	IFlowTable flowTable = workspaceConnection.getFlowTable();
    	for (IFlowEntry flowEntry : (List<IFlowEntry>) flowTable.deliverTargets()) {
    		try {
	    		IFlowNode targetFlowNode = (IFlowNode) fetchCompleteItem(flowEntry.getFlowNode());
	    		if (targetFlowNode instanceof IWorkspace) {
	        		IWorkspace targetWorkspace = (IWorkspace) targetFlowNode;
	        		indentedPrintf(" delivers to: %s\n", flowEntry.getFlowNode().getItemId().getUuidValue(), targetWorkspace.getName());
	    		} else {
	    			indentedPrintf(" delivers to: %s\n", flowEntry.getFlowNode().getItemId().getUuidValue());
	    		}
    		} catch (ItemNotFoundException e) {
    			
    		}
    	}
    	subtractIndent();
    }
    
    public void indentedPrintf(String format, Object... args) {
    	System.out.printf(indent() + format, args);
    }
    
    public IItem fetchCompleteItem(IItemHandle handle) throws TeamRepositoryException {
    	return repository.itemManager().fetchCompleteItem(handle, IItemManager.DEFAULT, monitor);
    }
    
    public IContributor lookupContributor(IContributorHandle contributorHandle) throws TeamRepositoryException {
    	return (IContributor) fetchCompleteItem(contributorHandle);
    }
    
    int indentLevel = 0;
    String indentStr = "                                                          ";
    
    public void addIndent() {
    	indentLevel += 1;
    }
    
    public void subtractIndent() {
    	indentLevel -= 1;
    }
    
    public String indent() {
    	return indentStr.substring(0, indentLevel*2);
    }
    
    public void listMembers(IProcessArea area) throws TeamRepositoryException {
    	 for (IContributorHandle ch: area.getMembers()) {
         	IContributor contributor = (IContributor) repository.itemManager().fetchCompleteItem(ch, IItemManager.DEFAULT, monitor);
         	if (contributor != null) {
         		System.out.format("  userid %1$s name %2$s\n", contributor.getUserId(), contributor.getName());
         	} else {
         		System.out.format("  user: " + ch);
         	}
         	System.out.println();
         }
    }
}
